package com.zwan.oam_rtc.service;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zwan.oam_rtc.bean.OamSettings;
import com.zwan.oam_rtc.bean.entity.FSMStatus;
import com.zwan.oam_rtc.bean.entity.UserFSM;
import com.zwan.oam_rtc.constants.Const;
import com.zwan.oam_rtc.imps.JavaImp;
import com.zwan.oam_rtc.imps.UserStatusHandler;
import com.zwan.oam_rtc.utils.messages.RtcmsBCSM;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class IVRService {

    @Autowired
    OamSettings oamSettings;

    @Autowired
    NumberAnalysisService numberAnalysisService;

    private boolean registerd_status = false;

    private ConcurrentHashMap<String, UserFSM> user_fsm_map = new ConcurrentHashMap<String, UserFSM>();

    private UserStatusHandler getJimpHandler() {
        JavaImp jimp = JavaImp.getInstance();
        return (UserStatusHandler) jimp.getHandlerInstance(UserStatusHandler.class);
    }

    private String registeIVRController() {
        UserStatusHandler handler = getJimpHandler();
        return handler.sendMessage2Rtcms((short) Const.OAM_COMMAND_REGISTER_IVR_CONTROLLER, JSON.toJSONString(null),
                false);
    }

    public void networkConnected() {
        registeIVRController();
    }

    public void setStatus(String result) {
        JSONObject jsonObject = JSONObject.parseObject(result);
        if (jsonObject.getString("error_code").equals("200")) {
            log.info("=== set ivr controller success ===");
            registerd_status = true;
        }
    }

    private void HandleCallBCSM(String data) {
        JSONObject jsonBody = JSONObject.parseObject(data);
        String caller = jsonBody.getString("caller");
        String callee = jsonBody.getString("callee");
        String ua = jsonBody.getString("ua");
        String ip = jsonBody.getString("ip");
        Integer port = jsonBody.getInteger("port");
        String sdp = jsonBody.getString("sdp");
        short type = jsonBody.getShortValue("type");

        if (type == Const.partcipation_type_sip_phone && !oamSettings.getAllowUser().contains(caller)) {
            log.info("caller:" + caller + " callee:" + callee + " ua:" + ua + " is forbidden");
            return;
        }
        log.info("caller:" + caller + " callee:" + callee + " ua:" + ua + " init call");
        String room = caller;

        if (user_fsm_map.get(caller) != null) {
            user_fsm_map.remove(caller);
        }
        UserFSM userFSM = new UserFSM();
        userFSM.setCaller(caller);
        userFSM.setCallee(callee);
        userFSM.setUa(ua);
        userFSM.setIp(ip);
        userFSM.setPort(port);
        userFSM.setSdp(sdp);
        userFSM.setType(type);
        userFSM.setStatus(FSMStatus.CALLING);
        userFSM.setRoom_name(room);
        user_fsm_map.put(caller, userFSM);

        // 开始进行号码分析
        if (!numberAnalysisService.analysis(userFSM)) {
            // 号码分析出错，直接释放呼叫
            userFSM.setStatus(FSMStatus.ERROR);
        }
        SendForwardCallReq(userFSM, true, true);
    }

    private void HandleActiveBCSM(String data) {
        JSONObject jsonBody = JSONObject.parseObject(data);
        String caller = jsonBody.getString("caller");
        String callee = jsonBody.getString("callee");
        log.info("caller:" + caller + " callee:" + callee + " active call");
        UserFSM userFSM = user_fsm_map.get(caller);
        if (userFSM == null) {
            return;
        }

        userFSM.setStatus(FSMStatus.ACTIVE);

        if (userFSM.getType() == Const.partcipation_type_sip_phone) {
            SendCompositeReq(userFSM.getRoom_name(), "eachother", userFSM.getCaller(), userFSM.getForward_calling());
        } else if (userFSM.getType() == Const.partcipation_type_sip_volte) {
            SendUserRouteDataReq(userFSM, "VIP");
        }
    }

    private void HandleDTMFBCSM(String data) {
        JSONObject jsonBody = JSONObject.parseObject(data);
        String caller = jsonBody.getString("caller");
        Integer dtmf = jsonBody.getInteger("dtmf");
        String target = jsonBody.getString("target");
        log.info("caller:" + caller + " dtmf:" + dtmf + " target:" + target);
        UserFSM userFSM = user_fsm_map.get(caller);
        if (userFSM == null) {
            return;
        }
        switch (userFSM.getIvvr_menu()) {
            case "zj1-1":
                if (dtmf == 1) { // 进入子菜单
                    userFSM.setIvvr_menu("zj2");
                    SendPACReq(userFSM, "ivvr/zj2.mp4", false, false);
                } else if (dtmf == 5) { // 进入子菜单
                    userFSM.setIvvr_menu("zj3");
                    SendPACReq(userFSM, "ivvr/zj3.mp4", true, false);
                } else if (dtmf == 8) { // 输入密码
                    userFSM.setIvvr_menu("zj161");
                    userFSM.setDtmf_list(new ArrayList<Integer>());
                    SendPACReq(userFSM, "ivvr/zj161.mp4", true, false);
                } else if (dtmf == 0) {
                    // 人工服务，route_data称为随路数据，可携带用户的队列tag和其它业务数据，坐席侧根据这些数据选择接听
                    SendUserRouteDataReq(userFSM, "VIP");
                }
                break;
            case "zj2":
                if (dtmf == 10) { // 回主菜单
                    userFSM.setIvvr_menu("zj1-1");
                    SendPACReq(userFSM, "ivvr/zj1-1.mp4", true, false);
                }
                break;
            case "zj3":
                if (dtmf == 10) { // 回主菜单
                    userFSM.setIvvr_menu("zj1-1");
                    SendPACReq(userFSM, "ivvr/zj1-1.mp4", true, false);
                }
                break;
            case "zj161": // 接收密码中
                if (dtmf == 11) { // #号
                    if (userFSM.getDtmf_list().size() == 6) {
                        // 接收密码完成
                        String dtmf_str = userFSM.getDtmf_list().toString();
                        dtmf_str = dtmf_str.replace("[", "")
                                .replace("]", "")
                                .replace(",", "")
                                .replace(" ", "");
                        log.info("recv dtmf:" + dtmf_str);
                        userFSM.getDtmf_list().clear(); // 使用完dtmf后清空dtmf缓存
                    } else {
                        userFSM.setIvvr_menu("zj162");
                        SendPACReq(userFSM, "ivvr/zj162.mp4", true, false);
                    }
                } else {
                    userFSM.getDtmf_list().add(dtmf);
                }

                break;
            default:
                break;
        }
    }

    private void HandlePACBCSM(String data) {
        JSONObject jsonBody = JSONObject.parseObject(data);
        String caller = jsonBody.getString("caller");
        String file_name = jsonBody.getString("file_name");
        String status = jsonBody.getString("status"); // progress 或者 finish
        UserFSM userFSM = user_fsm_map.get(caller);
        if (userFSM == null) {
            return;
        }

        if (status.equals("finish")) {
            log.info("caller:" + caller + " play stop:" + file_name);
            if (file_name.startsWith("ivvr/zj2.mp4")) {
                userFSM.setIvvr_menu("332-01");
                SendPACReq(userFSM, "ivvr/332-01.mp4", false, false);
            } else if (file_name.startsWith("ivvr/332-01.mp4")) {
                userFSM.setIvvr_menu("332-02");
                SendPACReq(userFSM, "ivvr/332-02.mp4", false, false);
            } else if (file_name.startsWith("ivvr/332-02.mp4")) {
                userFSM.setIvvr_menu("332-01");
                SendPACReq(userFSM, "ivvr/332-01.mp4", false, false);
            } else {
                log.info("caller:" + caller + " play stop:" + file_name + " is ignored");
            }
        } else if (status.equals("progress")) {
            log.info("caller:" + caller + " play progress:" + file_name);
            userFSM.setIvvr_menu_with_id(file_name);
        }
    }

    private short GetCallLegType(UserFSM userFSM, String calling, String called) {
        if (userFSM.getCallee().equals(called) && userFSM.getCaller().equals(calling)) {
            return Const.leg_type_A;
        } else if (userFSM.getForward_called().equals(called) && userFSM.getForward_calling().equals(calling)) {
            return Const.leg_type_B;
        } else {
            return Const.leg_type_none;
        }
    }

    private void HandleTerminateBCSM(String data) {
        JSONObject jsonBody = JSONObject.parseObject(data);
        String caller = jsonBody.getString("caller");
        String callee = jsonBody.getString("callee");
        log.info("caller:" + caller + " call: " + callee + " terminated");

        UserFSM userFSM = user_fsm_map.get(caller);
        if (userFSM == null) { // 对于坐席外呼流程，或者是中继转呼的情况没有记录UserFSM信息
            // 检查转呼腿释放的情况
            for (UserFSM u : user_fsm_map.values()) {
                if (caller.equals(u.getForward_calling()) && callee.equals(u.getForward_called())) {
                    userFSM = u;
                    break;
                }
            }
        }
        if (userFSM == null) {
            log.info("can not found session for " + "caller:" + caller + " called: " + callee);
            return;
        }

        short terminatedType = GetCallLegType(userFSM, caller, callee);

        if (terminatedType == Const.leg_type_A) {
            // A-LEG释放
            if (userFSM.getType() == Const.partcipation_type_sip_volte) {
                log.info("release A-Leg trunk: " + userFSM.getCaller());
            } else if (userFSM.getType() == Const.partcipation_type_sip_phone) {
                log.info("release A-Leg device: " + userFSM.getCaller());
            }
            // 关联释放B-LEG
            if (userFSM.getForward_calling() == null) {
                return;
            }
            if (userFSM.getForward_type() == Const.partcipation_type_sip_volte) {
                log.info("release B-Leg trunk: " + userFSM.getForward_calling() + "-" + userFSM.getForward_called());
                SendTerminateCallReq(userFSM.getRoom_name(), userFSM.getForward_calling(), userFSM.getForward_called());
                numberAnalysisService.returnNumber(userFSM);
            } else if (userFSM.getForward_type() == Const.partcipation_type_sip_phone) {
                log.info("release B-Leg device: " + userFSM.getForward_calling() + "-" + userFSM.getForward_called());
                SendTerminateCallReq(userFSM.getRoom_name(), userFSM.getForward_calling(), userFSM.getForward_called());
            }
            userFSM.setForward_called(null);
            userFSM.setForward_calling(null);

        } else if (terminatedType == Const.leg_type_B) {
            // B-LEG释放
            if (userFSM.getForward_type() == Const.partcipation_type_sip_volte) {
                log.info("release B-Leg trunk: " + userFSM.getForward_calling());
                numberAnalysisService.returnNumber(userFSM);
            } else if (userFSM.getForward_type() == Const.partcipation_type_sip_phone) {
                log.info("release B-Leg device: " + userFSM.getForward_called());
            }
            userFSM.setForward_called(null);
            userFSM.setForward_calling(null);

            // 关联释放A-LEG
            if (userFSM.getType() == Const.partcipation_type_sip_volte) {
                log.info("release A-Leg trunk: " + userFSM.getCaller());
                SendTerminateCallReq(userFSM.getRoom_name(), userFSM.getCaller(), userFSM.getCallee());
                numberAnalysisService.returnNumber(userFSM);
            } else if (userFSM.getType() == Const.partcipation_type_sip_phone) {
                log.info("release A-Leg device: " + userFSM.getCaller());
                SendTerminateCallReq(userFSM.getRoom_name(), userFSM.getCaller(), userFSM.getCallee());
            }
        } else {
            log.error("can not get leg type caller: " + caller + " called: " + callee);
        }
        log.info("caller:" + caller + " info cleanup");
        user_fsm_map.remove(caller);
    }

    private void HandleForwardCallBCSM(String data) {
        JSONObject jsonBody = JSONObject.parseObject(data);
        String caller = jsonBody.getString("caller");
        String callee = jsonBody.getString("callee");
        Integer status = jsonBody.getInteger("status");

        UserFSM userFSM = user_fsm_map.get(caller);

        if (userFSM == null) {
            log.info("can not found phone: " + caller + " bcsm: " + status);
            return;
        }

        log.info(String.format("org:%s -> %s; forward:%s -> %s status:%d",
                caller, callee, userFSM.getForward_calling(), userFSM.getForward_called(), status));

        if (userFSM.getForward_type() == Const.partcipation_type_sip_volte) {
            if (status == 183) {
                SendCallResult(userFSM);
            }
            else if(status == 200) {
                // 被叫话机应答，停止路由到坐席，停止播放，指定大画面
                SendCancelRouteReq("answered", userFSM.getForward_calling(), userFSM.getForward_called(),
                        userFSM.getForward_type());
                SendPACReq(userFSM, userFSM.getIvvr_menu_with_id(), false, true);
                SendCompositeReq(userFSM.getRoom_name(), "eachother",
                        userFSM.getCaller() + "-" + userFSM.getCallee(),
                        userFSM.getForward_calling() + "-" + userFSM.getForward_called());
            }
        } else if (userFSM.getForward_type() == Const.partcipation_type_sip_phone) {
            if (status == 180 || status == 404) { // 404表示自动应答终端不在线，继续正常呼叫
                SendCallResult(userFSM);
            } else if (status == 200) { // 被叫话机应答，停止路由到坐席，停止播放，指定大画面
                SendCancelRouteReq("answered", userFSM.getForward_calling(), userFSM.getForward_called(),
                        userFSM.getForward_type());
                SendPACReq(userFSM, userFSM.getIvvr_menu_with_id(), false, true);
                SendCompositeReq(userFSM.getRoom_name(), "eachother",
                        userFSM.getCaller() + "-" + userFSM.getCallee(),
                        userFSM.getForward_calling() + "-" + userFSM.getForward_called());
            }
        } else {
            log.info(String.format("unsupport type"));
        }
    }

    // 接收来自于媒体服务器的BCSM事件通知
    public void HandleBCSM(RtcmsBCSM bcsm) {
        switch (bcsm.getEvent()) {
            case Const.OAM_COMMAND_IVR_CALL_BCSM: // 呼入事件，需要指示媒体服务器是否继续接听
                HandleCallBCSM(bcsm.getBody());
                break;
            case Const.OAM_COMMAND_IVR_ACTIVE_BCSM: // 媒体接通事件
                HandleActiveBCSM(bcsm.getBody());
                break;
            case Const.OAM_COMMAND_IVR_PAC_BCSM: // 播放进度事件
                HandlePACBCSM(bcsm.getBody());
                break;
            case Const.OAM_COMMAND_IVR_DTMF_BCSM: // 收到用户按键事件
                HandleDTMFBCSM(bcsm.getBody());
                break;
            case Const.OAM_COMMAND_IVR_ROUTE_BCSM: // 被坐席接听事件
                break;
            case Const.OAM_COMMAND_IVR_TERMINATE_BCSM: // 终端挂机事件
                HandleTerminateBCSM(bcsm.getBody());
                break;
            case Const.OAM_COMMAND_FORWARD_CALL_OUT_BCSM: // 外呼状态事件
                HandleForwardCallBCSM(bcsm.getBody());
                break;
            default:
                break;
        }
    }

    // 鉴权通过，允许接通
    private void SendCallResult(UserFSM user) {
        if (!registerd_status)
            return;
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("caller", user.getCaller());
        resuJsonObject.put("callee", user.getCallee());
        resuJsonObject.put("sdp", user.getSdp());
        resuJsonObject.put("ip", user.getIp());
        resuJsonObject.put("port", user.getPort());
        resuJsonObject.put("ua", user.getUa());
        resuJsonObject.put("type", user.getType());
        resuJsonObject.put("status", user.getStatus().getValue());
        resuJsonObject.put("room", user.getRoom_name());
        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_IVR_CALL_REQ, JSON.toJSONString(resuJsonObject), false);
    }

    // IVVR服务中的播放和收号请求
    private void SendPACReq(UserFSM user, String file_name, boolean bloop, boolean iscancel) {
        if (!registerd_status)
            return;
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("caller", user.getCaller());
        resuJsonObject.put("callee", user.getCallee());
        resuJsonObject.put("filename", file_name==null?"none":file_name);
        resuJsonObject.put("loop", bloop);
        resuJsonObject.put("iscancel", iscancel);
        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_IVR_PAC_REQ, JSON.toJSONString(resuJsonObject), false);
    }

    // 给用户补充标签或其它附加业务数据，坐席依据标签或用户数据选择接听
    private void SendUserRouteDataReq(UserFSM user, String route_data) {
        if (!registerd_status)
            return;
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("caller", user.getCaller());
        resuJsonObject.put("callee", user.getCallee());
        resuJsonObject.put("data", route_data);
        resuJsonObject.put("ringfile", "ivvr/1_1_YXHH_02.mp4"); // 媒体服务器上的/home/rtcms/record/ivvr/1_1_YXHH_02.mp4
        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_IVR_ROUTE_REQ, JSON.toJSONString(resuJsonObject), false);
    }

    // 发起通过中继进行外呼
    private void SendForwardCallReq(UserFSM user, boolean audio, boolean video) {
        if (!registerd_status) {
            return;
        }
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("forwardcalling", user.getForward_calling()); // 中继的主叫号码
        resuJsonObject.put("forwardcalled", user.getForward_called()); // 中继的被叫号码
        resuJsonObject.put("forwardtype", user.getForward_type()); // 中继的被叫号码
        resuJsonObject.put("caller", user.getCaller()); // 原始主叫号码
        resuJsonObject.put("callee", user.getCallee()); // 原始被叫号码
        resuJsonObject.put("type", user.getType());
        resuJsonObject.put("status", user.getStatus().getValue());
        resuJsonObject.put("sdp", user.getSdp());

        if (user.getForward_type() == Const.partcipation_type_sip_volte) {
            resuJsonObject.put("ip", user.getForward_ip());
            resuJsonObject.put("port", user.getForward_port());
            resuJsonObject.put("localmediapublicip", user.getForward_local_media_public_ip());
        } else if (user.getForward_type() == Const.partcipation_type_sip_phone) {
            resuJsonObject.put("ip", "");
            resuJsonObject.put("port", 0);
            resuJsonObject.put("localmediapublicip", "");
        }

        resuJsonObject.put("audio", audio);
        resuJsonObject.put("video", video);
        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_FORWARD_CALL_OUT_REQ, JSON.toJSONString(resuJsonObject),
                false);
    }

    private void SendTerminateCallReq(String room, String caller, String called) {
        if (!registerd_status) {
            return;
        }
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("room", room);
        resuJsonObject.put("caller", caller);
        resuJsonObject.put("callee", called);
        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_IVR_TERMINATE_REQ, JSON.toJSONString(resuJsonObject),
                false);
    }

    private void SendCompositeReq(String room, String type, String p1, String p2) {
        if (!registerd_status) {
            return;
        }
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("room", room);
        resuJsonObject.put("type", type);
        JSONArray participants = new JSONArray();
        participants.add(p1);
        participants.add(p2);
        resuJsonObject.put("participants", participants);
        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_COMPOSITE_REQ, JSON.toJSONString(resuJsonObject),
                false);
    }

    private void SendCancelRouteReq(String status, String forward_caller, String forward_called, short forward_type) {
        JSONObject resuJsonObject = new JSONObject();
        resuJsonObject.put("status", status);
        resuJsonObject.put("caller", forward_caller);
        resuJsonObject.put("callee", forward_called);
        resuJsonObject.put("type", forward_type);

        UserStatusHandler handler = getJimpHandler();
        handler.sendIVRRequest2Rtcms((short) Const.OAM_COMMAND_IVR_CANCEL_ROUTE_REQ, JSON.toJSONString(resuJsonObject),
                false);
    }
}
